package com.kmxd.ams.app.archive;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.kmxd.ams.client.archive.IArchiveWatermarkSvc;
import com.kmxd.ams.client.archive.dto.ArchiveWatermarkAddDTO;
import com.kmxd.ams.client.archive.dto.ArchiveWatermarkEditDTO;
import com.kmxd.ams.client.archive.dto.ArchiveWatermarkQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveWatermarkListVO;
import com.kmxd.ams.client.archive.vo.ArchiveWatermarkVO;
import com.kmxd.ams.client.oss.vo.EfileRecordVO;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.client.watermark.IWatermarkSvc;
import com.kmxd.ams.core.common.constant.CacheConst;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.oss.template.OssTemplate;
import com.kmxd.ams.core.util.*;
import com.kmxd.ams.infra.archive.entity.ArchiveWatermark;
import com.kmxd.ams.infra.archive.mapper.ArchiveWatermarkMapper;
import com.yh.scofd.agent.HTTPAgent;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.IntStream;

/**
 * 水印管理表 服务实现类
 *
 * @author nickbi
 * @since 2022-09-19
 */
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = CacheConst.CACHE_PREFIX_ARCHIVE_WATERMARK)
public class ArchiveWatermarkSvcImpl extends ServiceImpl<ArchiveWatermarkMapper, ArchiveWatermark>
    implements IArchiveWatermarkSvc {

  private final ArchiveWatermarkMapper archiveWatermarkMapper;
  private final ISysConfigSvc sysConfigSvc;
  private final OssTemplate ossTemplate;

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public Page<ArchiveWatermarkListVO> selectPage(Page reqPage, ArchiveWatermarkQueryDTO req) {
    LambdaQueryWrapper<ArchiveWatermark> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveWatermark>(), req).lambda();
    Page<ArchiveWatermark> page = archiveWatermarkMapper.selectPage(reqPage, queryWrapper);
    Page<ArchiveWatermarkListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), ArchiveWatermarkListVO.class));
    return voPage;
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public List<ArchiveWatermarkListVO> selectList(ArchiveWatermarkQueryDTO req) {
    LambdaQueryWrapper<ArchiveWatermark> queryWrapper =
        QueryGen.init(new QueryWrapper<ArchiveWatermark>(), req).lambda();
    List<ArchiveWatermark> list = archiveWatermarkMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, ArchiveWatermarkListVO.class);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(ArchiveWatermarkAddDTO req) {
    req.setFondsId(
        ObjectUtil.isNotEmpty(req.getFondsId()) ? req.getFondsId() : SecurityUtil.getFondsId());
    ArchiveWatermark entity = BeanUtil.copyProperties(req, ArchiveWatermark.class);
    saveOrUpdate(entity);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(ArchiveWatermarkEditDTO req) {
    ArchiveWatermark entity = BeanUtil.copyProperties(req, ArchiveWatermark.class);
    archiveWatermarkMapper.updateById(entity);
  }

  @CacheEvict(allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    this.baseMapper.deleteBatchIds(idList);
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public ArchiveWatermarkVO view(Long id) {
    ArchiveWatermark entity = archiveWatermarkMapper.selectById(id);
    return BeanUtil.copyProperties(entity, ArchiveWatermarkVO.class);
  }

  @SneakyThrows
  @Override
  public String preview(Long id) {
    String contentByKey = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_OFD_PLUGIN);
    String view = ConfigUtil.getVal(contentByKey, ConfigConst.OFD_VIEW);
    if (cn.hutool.core.util.StrUtil.isBlank(view)) {
      view = "pdfjs";
    }
    String previewPath = ossTemplate.separator() + "preview";
    String fileType = Objects.equals("pdfjs", view) ? "pdf" : "ofd";
    ArchiveWatermark watermark = getById(id);
    String fileName = "previewDemo." + fileType;
    String watermarkFileName =
        Optional.ofNullable(
                    Optional.ofNullable(watermark).orElse(new ArchiveWatermark()).getArchTypeId())
                .orElse(0L)
            + "-"
            + fileName;
    String basePath =
        ossTemplate.getAttachmentPath(null)
            + ossTemplate.getAttachmentSubPath().getWatermarkPdf()
            + previewPath;
    String path = basePath + ossTemplate.separator() + fileName;
    String watermarkPath = basePath + ossTemplate.separator() + watermarkFileName;
    FileUtil.del(path);
    // 文件不存在，创建demo文件
    if (!ossTemplate.exist(basePath)) {
      ossTemplate.mkdir(basePath);
    }
    if (!ossTemplate.exist(path)) {
      if (Objects.equals("pdf", fileType)) {
        createPdfPreview(path);
      } else {
        String pdfPath = cn.hutool.core.util.StrUtil.replace(path, ".ofd", ".pdf");
        createPdfPreview(pdfPath);
        createOfdPreview(new File(pdfPath), path);
      }
    }

    if (Objects.isNull(watermark)) {
      return path;
    }

    if (BooleanUtil.isFalse(watermark.getEnabled())) {
      return path;
    }
    IWatermarkSvc watermarkSvc = SpringUtil.getBean(IWatermarkSvc.class);
    EfileRecordVO vo = new EfileRecordVO();
    vo.setArchTypeId(watermark.getArchTypeId());
    vo.setId(1L);
    vo.setPath(watermarkPath);
    vo.setArchId(watermark.getArchTypeId());
    vo.setFile(FileUtil.file(path));
    watermarkSvc.addWatermark(vo.getArchTypeId(), vo.getFile(), watermarkPath);
    return watermarkPath;
  }

  private void createPdfPreview(String path) {
    try {
      Document doc = new Document();
      PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(path));
      doc.open();
      byte[] font = ResourceUtil.readBytes(WatermarkUtil.findFonts());
      BaseFont base =
          BaseFont.createFont(
              "simfang.ttf",
              BaseFont.IDENTITY_H,
              BaseFont.NOT_EMBEDDED,
              BaseFont.NOT_CACHED,
              font,
              font);
      Font titleFont = new Font(base);
      titleFont.setColor(BaseColor.BLACK);
      titleFont.setSize(32);
      doc.add(new Paragraph("昆明信迪科技PDF文件预览", titleFont));
      Font contentFont = new Font(base);
      contentFont.setColor(BaseColor.BLACK);
      titleFont.setSize(12);
      IntStream.range(1, 20)
          .forEach(
              i -> {
                try {
                  Paragraph chapter = new Paragraph("段落" + i);
                  chapter.setPaddingTop(10);
                  doc.add(chapter);
                  Paragraph content =
                      new Paragraph(
                          RandomUtil.randomString(RandomUtil.randomInt(128)), contentFont);
                  doc.add(content);
                } catch (DocumentException e) {
                  log.error(e.getMessage(), e);
                }
              });
      doc.close();
      writer.close();
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }

  private void createOfdPreview(File pdfFile, String path) {
    try {
      HTTPAgent agent = new HTTPAgent(getUrl());
      FileOutputStream outputStream = new FileOutputStream(path);
      agent.pdfToOFD(FileUtil.readBytes(pdfFile), outputStream, null);
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }

  @Cacheable(keyGenerator = "myKeyGenerator")
  @Override
  public ArchiveWatermarkVO getByArchTypeId(Long archTypeId) {
    ArchiveWatermark one =
        getOne(
            Wrappers.<ArchiveWatermark>lambdaQuery()
                .eq(ArchiveWatermark::getArchTypeId, archTypeId));
    return ConvertUtil.toBean(one, ArchiveWatermarkVO.class);
  }

  public String getUrl() {
    String archSeal = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_TRANSFER);
    if (cn.hutool.core.util.StrUtil.isNotBlank(archSeal) && JSONUtil.isTypeJSON(archSeal)) {
      JSONObject sealSetting = JSONUtil.parseObj(archSeal);
      String transferURL = sealSetting.get("transferURL", String.class);
      getServeUrl(transferURL);
    }
    return null;
  }

  public String getServeUrl(String url) {
    if (CharSequenceUtil.isBlank(url)) {
      throw BizTipException.instance("转换地址不正确");
    }
    String[] split = url.split(";");
    if (split.length == 1) {
      return split[0];
    }
    try {
      int urlHashIndex = HashUtil.additiveHash(String.valueOf(SystemClock.now()), split.length);
      return split[urlHashIndex];
    } catch (Exception e) {
      e.printStackTrace();
      throw BizTipException.instance("转换地址不正确");
    }
  }
}
